/**
 * 
 */
package es.twentymobile.mule.modules.jpa.xa;

import javax.persistence.EntityManager;
import javax.sql.XAConnection;
import javax.transaction.xa.XAResource;

import org.mule.api.transaction.Transaction;
import org.mule.api.transaction.TransactionException;
import org.mule.config.i18n.CoreMessages;
import org.mule.transaction.IllegalTransactionStateException;
import org.mule.transaction.TransactionCoordination;
import org.mule.transaction.XaTransaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author alvarezjm
 * 
 */
public class JpaXaResourceForTomcatAndOpenJpa extends JpaXaResource {

	private Boolean enlisted;

	private static Logger log = LoggerFactory.getLogger(JpaXaResourceForTomcatAndOpenJpa.class);

	public boolean isEnlisted() {
		return enlisted;
	}

	public EntityManager getEntityManager() {
		return impl;
	}

	public JpaXaResourceForTomcatAndOpenJpa(EntityManager s) {
		super(s);
		this.enlisted = Boolean.FALSE;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.mule.transaction.XaTransaction.MuleXaObject#enlist()
	 */
	@Override
	public boolean enlist() throws TransactionException {
		if (isEnlisted()) {
			return false;
		}
		if (log.isDebugEnabled()) {
			log.debug("Enlistment request");
		}

		Transaction transaction = TransactionCoordination.getInstance().getTransaction();
		if (transaction == null) {
			throw new IllegalTransactionStateException(CoreMessages.noMuleTransactionAvailable());
		}
		if (!(transaction instanceof XaTransaction)) {
			throw new IllegalTransactionStateException(CoreMessages.notMuleXaTransaction(transaction));
		}
		if (!isEnlisted()) {
			XAResource xaResource;
			try {
				XAConnection conn = ((org.apache.openjpa.jdbc.kernel.JDBCStoreManager.ClientConnection) (impl
						.unwrap(org.apache.openjpa.persistence.EntityManagerImpl.class)).getConnection()).getInnermostDelegate().unwrap(XAConnection.class);
				if (conn != null) {
					xaResource = ((XAConnection) conn).getXAResource();
					enlisted = ((XaTransaction) transaction).enlistResource(xaResource);
					if (log.isDebugEnabled()) {
						log.debug("Enlistment result: " + enlisted);
					}
				} else {
					log.error("Connection is null, cannot enlist");
					return true;
				}
			} catch (Exception e) {
				throw new TransactionException(e);
			}

		}
		return enlisted;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.mule.transaction.XaTransaction.MuleXaObject#delist()
	 */
	@Override
	public boolean delist() throws Exception {
		if (!isEnlisted()) {
			return false;
		}
		if (log.isDebugEnabled()) {
			log.debug("Delistment request");
		}

		Transaction transaction = TransactionCoordination.getInstance().getTransaction();
		if (transaction == null) {
			throw new IllegalTransactionStateException(CoreMessages.noMuleTransactionAvailable());
		}
		if (!(transaction instanceof XaTransaction)) {
			throw new IllegalTransactionStateException(CoreMessages.notMuleXaTransaction(transaction));
		}
		if (isEnlisted() && transaction.isXA()) {
			XAConnection conn = ((org.apache.openjpa.jdbc.kernel.JDBCStoreManager.ClientConnection) (impl
					.unwrap(org.apache.openjpa.persistence.EntityManagerImpl.class)).getConnection()).getInnermostDelegate().unwrap(XAConnection.class);

			if (conn != null) {
				XAResource xaResource = ((XAConnection) conn).getXAResource();
				enlisted = !((XaTransaction) transaction).delistResource(xaResource, XAResource.TMSUCCESS);
				if (log.isDebugEnabled()) {
					log.debug("Delistment result: " + enlisted);
				}
			} else {
				log.error("Connection is null, cannot delist");
				return true;
			}
		}
		return !isEnlisted();
	}

}
